/**
 * ****************************************************************************
 * Project: RoboBridge
 * ----------------------------------------------------------------------------
 * -------------------------- [c]2012 - KrawallMann ---------------------------
 * ---------------------- http://www.krawallmann.de.tc/ -----------------------
 * ****************************************************************************
 * File: AbstractProtocolState.java Package:
 * tc.de.krawallmann.robobridge.communication.protocol Version: 1.0 Author(s):
 * KrawallMann
 * ****************************************************************************
 * Description:
 * ****************************************************************************
 */
package tc.de.krawallmann.robobridge.communication.protocol;

import java.util.logging.Level;

import tc.de.krawallmann.robobridge.communication.Command;
import tc.de.krawallmann.robobridge.communication.CommandType;
import tc.de.krawallmann.robobridge.communication.IncomingCommandListener;
import tc.de.krawallmann.robobridge.util.Log;

/**
 * The Class AbstractProtocolState is an abstraction of different
 * ProtocolStates.<br/>
 * The main logic is handled by those states.
 * 
 * @param <T>
 *            the generic type
 * @author KrawallMann
 * @version 1.0
 */
public abstract class AbstractProtocolState<T extends AbstractProtocol> implements
		IncomingCommandListener {

	/** The last heartbeat. */
	private transient static long lastHeartbeat;

	/** The protocol. */
	protected transient final T protocol;

	/**
	 * Instantiates a new abstract protocol state.
	 * 
	 * @param protocol
	 *            the protocol
	 */
	public AbstractProtocolState(final T protocol) {
		super();
		this.protocol = protocol;
		protocol.addIncomingCommandListener(this);
	}
	
	

	/**
	 * Close.
	 */
	public void close() {
		protocol.removeIncomingCommandListener(this);
		lastHeartbeat=0;
	}

	/**
	 * Gets the protocol.
	 * 
	 * @return the protocol
	 */
	public AbstractProtocol getProtocol() {
		return protocol;
	}

	/**
	 * Checks if is complete.
	 * 
	 * @return true, if is complete
	 */
	public abstract boolean isComplete();

	/**
	 * Checks if is failed.
	 * 
	 * @return true, if is failed
	 */
	public boolean isFailed() {
		return System.currentTimeMillis() - AbstractProtocolState.lastHeartbeat >= 2000
				&& AbstractProtocolState.lastHeartbeat != 0;
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * basepackage.IncomingCommandListener#onCommandReceived(basepackage.Command
	 * )
	 */
	@Override
	public boolean onCommandReceived(final Command command) {
		if (command.getType() == CommandType.HEARTBEAT) {
			AbstractProtocolState.lastHeartbeat = System.currentTimeMillis();
			try {
				getProtocol().sendCommand(new Command(CommandType.HEARTBEAT, false));
			} catch (final InterruptedException exc) {
				// Should not happen - no ACK required
				Log.log(Level.INFO, getClass(), "onCommandReceived",
						"Exception while sending Heartbeat - {0}!", exc.getMessage());
			}
			return true;
		}
		return false;
	}

	/**
	 * Update.
	 */
	public abstract void update();
}
